package com.gs.mp.db.utils;

import com.google.common.collect.Lists;
import com.gs.common.tool.consts.AttributeConst;
import com.gs.common.tool.consts.DbDriverConst;
import com.gs.common.tool.consts.TagConst;
import com.gs.common.tool.pojo.ColumnInfo;
import com.gs.common.tool.pojo.TableInfo;
import com.gs.common.tool.pojo.TableTagInfo;
import com.gs.common.tool.utils.*;
import com.gs.mp.db.config.JdbcConnection;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.sql.Connection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * java文件生成工具
 *
 * @author: guos
 * @date: 2024/09/03 11:57
 **/
public class GenerateJavaUtil {


    /**
     * 生成java类
     *
     * @param ddType              数据源
     * @param configFilePath      配置文件路径
     * @param dbDriverJarFilePath 驱动文件路径
     * @date 2024/09/03 12:00
     **/
    public static List<String> generate(String ddType, String configFilePath, String dbDriverJarFilePath) throws DocumentException {
        List<String> errorList = Lists.newArrayList();
        //解析配置文件
        Document document = new SAXReader().read(new File(configFilePath));
        Element context = document.getRootElement().element(TagConst.context);
        if (Objects.isNull(context)) {
            errorList.add(String.format("%s element tag is not null!%n", TagConst.context));
            return errorList;
        }
        List<Element> elements = context.elements();
        if (CollectionUtil.isEmpty(elements)) {
            errorList.add(String.format("%s element tag must have child!", TagConst.context));
            return errorList;
        }
        Map<String, Element> elementMap = elements.stream().collect(Collectors.toMap(Element::getName, Function.identity(), (k1, k2) -> k2));
        Element author = elementMap.get(TagConst.author);
        Element baseInfoEle = elementMap.get(TagConst.baseInfo);
        Element entity = elementMap.get(TagConst.entity);
        Element mapper = elementMap.get(TagConst.mapper);
        Element mapperXml = elementMap.get(TagConst.mapperXml);
        Element service = elementMap.get(TagConst.service);
        Element serviceImpl = elementMap.get(TagConst.serviceImpl);
        Element controller = elementMap.get(TagConst.controller);
        Element tables = elementMap.get(TagConst.tables);
        //jdbc链接
        Element jdbcConnectionEle = elementMap.get(TagConst.jdbcConnection);
        if (Objects.isNull(jdbcConnectionEle)) {
            errorList.add(TagConst.jdbcConnection + " element tag is not null!");
            return errorList;
        }
        if (Objects.isNull(baseInfoEle)) {
            errorList.add(TagConst.baseInfo + " element tag is not null!");
            return errorList;
        }
        //获取jdbc信息
        JdbcConnection jdbcConnection = new JdbcConnection();
        jdbcConnection.setDriverClass(XmlUtil.getAttributeValue(jdbcConnectionEle, JdbcConnection.Fields.driverClass))
                .setConnectionURL(XmlUtil.getAttributeValue(jdbcConnectionEle, JdbcConnection.Fields.connectionURL))
                .setUserId(XmlUtil.getAttributeValue(jdbcConnectionEle, JdbcConnection.Fields.userId))
                .setPassword(XmlUtil.getAttributeValue(jdbcConnectionEle, JdbcConnection.Fields.password));
        String authorName = XmlUtil.getAttributeValue(author.attribute(AttributeConst.value));
        String basePathName = XmlUtil.getAttributeValue(baseInfoEle, AttributeConst.path);
        String basePackageName = XmlUtil.getAttributeValue(baseInfoEle, AttributeConst.pack);
        String entityPathName = XmlUtil.getPath(basePathName, entity);
        String entityPackageName = XmlUtil.getPackage(basePackageName, entity);
        String entitySuper = XmlUtil.getAttributeValue(entity.attribute(AttributeConst.superClass));

        String mapperPathName = XmlUtil.getPath(basePathName, mapper);
        String mapperPackageName = XmlUtil.getPackage(basePackageName, mapper);
        String mapperSuffix = PoJoUtil.firstToUpper(XmlUtil.getAttributeValue(mapper.attribute(AttributeConst.suffix)));
        String mapperSuper = XmlUtil.getAttributeValue(mapper.attribute(AttributeConst.superClass));

        String mapperXmlPathName = XmlUtil.getPath(basePathName, mapperXml);

        String servicePathName = XmlUtil.getPath(basePathName, service);
        String servicePackageName = XmlUtil.getPackage(basePackageName, service);
        String serviceSuffix = PoJoUtil.firstToUpper(XmlUtil.getAttributeValue(service.attribute(AttributeConst.suffix)));
        String serviceSuper = XmlUtil.getAttributeValue(service.attribute(AttributeConst.superClass));


        String serviceImpPathName = XmlUtil.getPath(basePathName, serviceImpl);
        String serviceImplPackageName = XmlUtil.getPackage(basePackageName, serviceImpl);
        String serviceImplSuffix = PoJoUtil.firstToUpper(XmlUtil.getAttributeValue(serviceImpl.attribute(AttributeConst.suffix)));
        String serviceImplSuper = XmlUtil.getAttributeValue(serviceImpl.attribute(AttributeConst.superClass));


        String controllerPathName = XmlUtil.getPath(basePathName, controller);
        String controllerPackageName = XmlUtil.getPackage(basePackageName, controller);
        String controllerSuffix = PoJoUtil.firstToUpper(XmlUtil.getAttributeValue(controller.attribute(AttributeConst.suffix)));
        String controllerSuper = XmlUtil.getAttributeValue(controller.attribute(AttributeConst.superClass));

        //根据获取连接
        Connection connection = DbUtil.getConnection(dbDriverJarFilePath, jdbcConnection);
        //遍历表
        tables.elements().forEach(t -> {
            String scheme = XmlUtil.getAttributeValue(t.attribute(TableTagInfo.Fields.scheme));
            String tableName = XmlUtil.getAttributeValue(t.attribute(TableTagInfo.Fields.tableName));
            String ds = XmlUtil.getAttributeValue(t.attribute(TableTagInfo.Fields.ds));
            String pojoPrefix = XmlUtil.getAttributeValue(t.attribute(TableTagInfo.Fields.pojoPrefix));
            String genPojo = XmlUtil.getAttributeValue(t.attribute(TableTagInfo.Fields.genPojo));
            String genXml = XmlUtil.getAttributeValue(t.attribute(TableTagInfo.Fields.genXml));
            String genMapper = XmlUtil.getAttributeValue(t.attribute(TableTagInfo.Fields.genMapper));
            String genService = XmlUtil.getAttributeValue(t.attribute(TableTagInfo.Fields.genService));
            String genServiceImpl = XmlUtil.getAttributeValue(t.attribute(TableTagInfo.Fields.genServiceImpl));
            String genController = XmlUtil.getAttributeValue(t.attribute(TableTagInfo.Fields.genController));
            String enableSuper = XmlUtil.getAttributeValue(t.attribute(TableTagInfo.Fields.enableSuper));
            if (StringUtil.isEmpty(scheme)) {
                errorList.add("table element tag scheme attribute is not null!");
                return;
            }
            TableInfo tableInfo;
            if (DbDriverConst.MYSQL.equals(ddType)) {
                tableInfo = DbUtil.getMysqlTableInfo(connection, scheme, tableName);
            } else if (DbDriverConst.POSTGRESQL.equals(ddType)) {
                tableInfo = DbUtil.getPgTableInfo(connection, scheme, tableName);
            } else if (DbDriverConst.SQL_SERVER.equals(ddType)) {
                tableInfo = DbUtil.getSqlSeverTableInfo(connection, scheme, tableName);
            } else {
                errorList.add(String.format("%s db type is not support !", ddType));
                return;
            }
            String tableComment = tableInfo.getComment();
            List<ColumnInfo> tableColumnInfoList = tableInfo.getColumnInfoList();
            if (CollectionUtil.isEmpty(tableColumnInfoList)) {
                errorList.add(String.format("table 【%s】列信息解析失败!", tableName));
                return;
            }
            //按照列索引升序
            tableColumnInfoList.sort(Comparator.comparing(ColumnInfo::getIndex));
            //实体类名
            String pojoName = PoJoUtil.getEntityName(pojoPrefix, tableName, XmlUtil.getAttributeValue(t.attribute(TableTagInfo.Fields.pojoName)));
            //生成实体类
            if (XmlUtil.isTrue(genPojo)) {
                JavaCodeGenUtil.genPojo(entityPathName, scheme, tableName, pojoName, entityPackageName, enableSuper, XmlUtil.getAttributeValue(entity.attribute(AttributeConst.enableSuper)), entitySuper, tableComment, tableColumnInfoList, authorName);
            }
            String entityFullName = String.format("%s.%s", entityPackageName, pojoName);
            String mapperFullName = String.format("%s.%s%s", mapperPackageName, pojoName, mapperSuffix);
            String serviceFullName = String.format("%s.I%s%s", servicePackageName, pojoName, serviceSuffix);
            //生成mapper
            if (XmlUtil.isTrue(genMapper)) {
                JavaCodeGenUtil.genMapper(mapperPathName, ds, entityFullName, mapperPackageName, enableSuper, XmlUtil.getAttributeValue(mapper.attribute(AttributeConst.enableSuper)), mapperSuper, tableComment, mapperSuffix, authorName);
            }
            //生成mapper-xml
            if (XmlUtil.isTrue(genXml)) {
                XmlUtil.generateMapperXml(mapperFullName, pojoName + mapperSuffix, mapperXmlPathName);
            }
            //生成service
            if (XmlUtil.isTrue(genService)) {
                JavaCodeGenUtil.genService(servicePathName, entityFullName, servicePackageName, serviceSuffix, enableSuper, XmlUtil.getAttributeValue(service.attribute(AttributeConst.enableSuper)), serviceSuper, tableComment, authorName);
            }
            //生成serviceImpl
            if (XmlUtil.isTrue(genServiceImpl)) {
                JavaCodeGenUtil.genServiceImpl(serviceImpPathName, ds, entityFullName, mapperFullName, serviceFullName, serviceImplPackageName, serviceImplSuffix, enableSuper, XmlUtil.getAttributeValue(serviceImpl.attribute(AttributeConst.enableSuper)), serviceImplSuper, tableComment, authorName);
            }
            //生成controller
            if (XmlUtil.isTrue(genController)) {
                JavaCodeGenUtil.genController(controllerPathName, entityFullName, serviceFullName, controllerPackageName, controllerSuffix, enableSuper, XmlUtil.getAttributeValue(controller.attribute(AttributeConst.enableSuper)), controllerSuper, tableComment, authorName);
            }
            errorList.add(String.format("table-->【%s】 generate successful !%n", StringUtil.isEmpty(scheme) ? tableName : String.format("%s.%s", scheme, tableName)));
        });
        //关闭链接
        DbUtil.closeConnection(connection);
        return errorList;
    }
}
